home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
-
- #include "acgi.h"
- #include "www.h"
-
- static char *gHTTPHeader =
- "HTTP/1.0 200 OK\r\n"
- "Server: WebSTAR/1.2.5\r\n"
- "MIME-version: 1.0\r\n"
- "Content-type: text/html\r\n\r\n";
-
- static long gHTTPHeaderLen;
-
- void ACGIInit(void);
- void ACGIEvent(EventRecord *theEvent);
- void ACGIPeriodicTask(void);
- void ACGIQuit(void);
-
- static Boolean gDone = false;
- static unsigned long gThreads = 0;
-
- static long gThreadSleep = 4;
- static long gIdleSleep = 0x7FFFFFFF;
- static long gWNEDelta = 8;
-
- void main(void)
- {
- EventRecord theEvent;
- long sleep;
- unsigned long nextWNE;
-
- ACGIInit(); // Initialize…
-
- // Main Event loop…
-
- while (!gDone || gThreads > 0) {
-
- if (gThreads > 0)
- sleep = gThreadSleep;
- else
- sleep = gIdleSleep;
-
- if (WaitNextEvent(everyEvent, &theEvent, sleep, nil))
- ACGIEvent(&theEvent);
-
- nextWNE = TickCount() + gWNEDelta;
-
- do {
- YieldToAnyThread();
- } while (TickCount() <= nextWNE);
-
- ACGIPeriodicTask();
- }
-
- ACGIQuit(); // Shutdown…
- }
-
- // -----------------------------------------------------
-
- // For additional checks for Thread Manager on PowerPC...
-
- #if GENERATINGCFM
- #include <codefragments.h>
- #endif
-
- // These prototypes are defined in "www.h"
- //
- // char *WWWGetLogName(void);
- // void WWWGetHTMLPages(char **refused, char **tooBusy,
- // char **noMemory, char **unexpectedError);
- // OSErr WWWInit(void);
-
- // This prototype is defined in "acgi.h"
- // void ACGILog(char *msg);
-
- void ACGIFatal(char *reason);
- void AEInstallHandlers(void);
-
- static FILE *gLog = NULL; // The log file…
-
- // Generic HTML error-response pages...
-
- static Handle gHTMLNoMemory = nil;
- static Handle gHTMLUnexpectedError = nil;
- static Handle gHTMLRefused = nil;
- static Handle gHTMLTooBusy = nil;
-
- #define kMaxMasters 20
-
- static void ACGIInit(void)
- {
- long i;
- OSErr err;
-
- // [1] Initialize the toolbox…
-
- MaxApplZone();
-
- for (i = 0; i < kMaxMasters; i++)
- MoreMasters();
-
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(nil);
- InitCursor();
-
- FlushEvents(everyEvent, 0);
-
- // [2] Open the log file using the name returned by WWWGetLogName().
-
- gLog = fopen(WWWGetLogName(), "a");
-
- // [3] See if we can run...
- //
- // …we need Apple Events (which means System 7.0 or later)…
-
- {
- SysEnvRec theSysEnv;
-
- err = SysEnvirons(curSysEnvVers, &theSysEnv);
-
- if (err != noErr || theSysEnv.systemVersion < 0x0700)
- ACGIFatal("AppleEvents unavailable.");
- }
-
- // …and the Thread Manager (with additional checks for a
- // loaded Thread Library when compiling for PPC).
-
- {
- long threadMgrAttr;
-
- err = Gestalt(gestaltThreadMgrAttr, &threadMgrAttr);
-
- if (
- err != noErr ||
- #if GENERATINGCFM
- threadMgrAttr & (1L << gestaltThreadsLibraryPresent) == 0 ||
- (Ptr) NewThread == (Ptr) kUnresolvedSymbolAddress ||
- #endif
- threadMgrAttr & (1L << gestaltThreadMgrPresent) == 0
- ) ACGIFatal("Thread Manager unavailable");
- }
-
- // [4] Build the menu bar from an MBAR resource...
-
- {
- #define kMenuBarResID 1000
-
- #define kAppleMenuResID 1000
- #define kFileMenuResID 1010
-
- Handle theBar;
- MenuHandle appleMenu;
-
- theBar = GetNewMBar(kMenuBarResID);
- if (theBar == nil) ACGIFatal("Could not load menu bar.");
-
- SetMenuBar(theBar);
-
- // Append the "Apple Menu Items" to the Apple menu and then draw it…
-
- appleMenu = GetMenuHandle(kAppleMenuResID);
- if (appleMenu == nil) ACGIFatal("Could not load Apple Menu.");
-
- AppendResMenu(appleMenu, 'DRVR');
- DrawMenuBar();
- }
-
- // [5] Install the event handlers (SDOC handler will be threaded)…
-
- AEInstallHandlers();
-
- // [6] Get the general HTML error response pages…
-
- gHTTPHeaderLen = strlen(gHTTPHeader);
-
- gHTMLRefused = NewHandle(gHTTPHeaderLen);
- if (gHTMLRefused == nil) ACGIFatal("Ran out of memory making gHTMLRefused.");
- BlockMoveData(gHTTPHeader, *gHTMLRefused, gHTTPHeaderLen);
-
- gHTMLTooBusy = NewHandle(gHTTPHeaderLen);
- if (gHTMLTooBusy == nil) ACGIFatal("Ran out of memory making gHTMLTooBusy.");
- BlockMoveData(gHTTPHeader, *gHTMLTooBusy, gHTTPHeaderLen);
-
- gHTMLNoMemory = NewHandle(gHTTPHeaderLen);
- if (gHTMLNoMemory == nil) ACGIFatal("Ran out of memory making gHTMLNoMemory.");
- BlockMoveData(gHTTPHeader, *gHTMLNoMemory, gHTTPHeaderLen);
-
- gHTMLUnexpectedError = NewHandle(gHTTPHeaderLen);
- if (gHTMLUnexpectedError == nil) ACGIFatal("Ran out of memory making gHTMLUnexpectedError.");
- BlockMoveData(gHTTPHeader, *gHTMLUnexpectedError, gHTTPHeaderLen);
-
- WWWGetHTMLPages(gHTMLRefused, gHTMLTooBusy,
- gHTMLNoMemory, gHTMLUnexpectedError);
-
- // [7] Give you a chance to set up your runtime environment
- // and get/set ACGI run parameters…
-
- {
- err = WWWInit();
-
- if (err != noErr) {
- char msg[64];
- sprintf(msg, "WWWInit() failed. Error code = %d", err);
- ACGIFatal(msg);
- }
- }
-
- // Write a startup message in the log…
-
- ACGILog("................................startup.");
- }
-
- // -----------------------------------------------------
-
- void ACGIFatal(char *reason)
- {
- if (gLog != NULL) {
- ACGILog(reason);
- ACGILog("That was a fatal error..........shutdown.");
- }
- ExitToShell();
- }
-
- void ACGILog(char *msg)
- {
- DateTimeRec dt;
- ThreadID theThread;
-
- if (gLog == NULL) return;
-
- GetTime(&dt);
- GetCurrentThread(&theThread);
- fprintf(gLog, "%4d/%02d/%02d\t%02d:%02d:%02d\t%010lu\t%s\n",
- dt.year, dt.month, dt.day,
- dt.hour, dt.minute, dt.second,
- theThread, msg);
- fflush(gLog);
- }
-
- // -----------------------------------------------------
-
- void ACGIPeriodicTask(void)
- {
- OSErr err = WWWPeriodicTask();
-
- if (err != noErr) {
- char msg[64];
-
- sprintf(msg, "WWWPeriodicTask returned error: %d");
- ACGILog(msg);
-
- if (err < 0) {
- ACGILog("That was a fatal error...quitting.");
- gDone = true;
- }
- }
- }
-
- static void ACGIQuit(void)
- {
- WWWQuit();
-
- ACGILog("................................shutdown.");
-
- if (gLog != NULL) fclose(gLog);
- }
-
- // -----------------------------------------------------
-
- void DoMenu(long menuResult);
-
- static void ACGIEvent(EventRecord *theEvent)
- {
- char msg[64];
- OSErr err;
-
- switch (theEvent->what) {
-
- // No windows...so we can ignore activate and update events...
-
- case activateEvt:
- case updateEvt:
- break;
-
- // The only mouse-downs will be in the menu bar or in
- // windows that don't belong to us...
-
- case mouseDown:
- {
- WindowPtr theWindow;
-
- switch (FindWindow(theEvent->where, &theWindow)) {
-
- case inMenuBar:
-
- DoMenu(MenuSelect(theEvent->where));
- break;
-
- case inSysWindow:
-
- SystemClick(theEvent, theWindow);
- break;
- }
- }
- break;
-
- // The only key-downs we'll get are menu-key equivalents...
-
- case keyDown:
- case autoKey:
- if ((theEvent->modifiers & cmdKey) != 0) {
- long menuResult = MenuKey(theEvent->message & charCodeMask);
-
- if (HiWord(menuResult) != 0) DoMenu(menuResult);
- }
- break;
-
- // Suspend or Resume event...just set the cursor to an arrow...
-
- case osEvt:
- if ((theEvent->message >> 24) & suspendResumeMessage)
- SetCursor(&qd.arrow);
- break;
-
- // Always handle disk-inserted events...be a well-behaved app!
-
- case diskEvt:
- if (HiWord(theEvent->message) != 0) {
- Point pt;
-
- SetPt(&pt, 120, 120);
-
- DILoad();
- err = DIBadMount(pt, theEvent->message);
- if (err != noErr) {
- sprintf(msg, "Main loop: DIBadMount() returned error: %d", err);
- ACGILog(msg);
- }
- DIUnload();
- }
- break;
-
- // Do AppleEvents like always...the threading is
- // invisible to the main event loop...
-
- case kHighLevelEvent:
- err = AEProcessAppleEvent(theEvent);
- if (err != noErr) {
- sprintf(msg, "Main loop: AEProcessAppleEvent() returned error: %d", err);
- ACGILog(msg);
- }
- break;
- }
-
- return;
- }
-
- // We do the "usual" menu stuff...except we don't do
- // the "About..." box thing...
- //
- // We do run desk accessories though...
- //
-
- #define kAboutItem 1
-
- static void DoMenu(long menuResult)
- {
- short theMenu = HiWord(menuResult);
- short theItem = LoWord(menuResult);
-
- switch (theMenu) {
-
- case kAppleMenuResID:
-
- if (theItem != kAboutItem) {
- MenuHandle appleMenu = GetMenuHandle(kAppleMenuResID);
-
- if (appleMenu != nil) {
- GrafPtr savePort;
- Str255 daName;
-
- GetPort(&savePort);
- SetCursor(&qd.arrow);
- GetMenuItemText(appleMenu, theItem, daName);
- OpenDeskAcc(daName);
- SetPort(savePort);
- }
- else {
- ACGILog("DoMenu: couldn't get Apple Menu handle.");
- }
- }
- break;
-
- case kFileMenuResID:
-
- gDone = true;
- break;
-
- }
-
- // Don't forget to unhilight the menu bar when we're done...
-
- HiliteMenu(0);
- }
-
- // -----------------------------------------------------
-
- #define kQuitCoreEvent 1
- #define kOtherCoreEvent 0
-
- pascal OSErr HandleAECore(AppleEvent *event, AppleEvent *reply, long refCon);
-
- static pascal OSErr HandleAECore(AppleEvent *event, AppleEvent *reply, long refCon)
- {
- if (refCon == kQuitCoreEvent) gDone = true;
-
- return (noErr);
- }
-
- // -----------------------------------------------------
-
- #define kWebSTAREventClass 'WWWΩ'
- #define kSDOCEvent 'sdoc'
-
- // Prototype for our SDOC handler routine.
-
- pascal OSErr HandleSDOC(AppleEvent *event, AppleEvent *reply, long refCon);
-
- // -----------------------------------------------------
-
- static void AEInstallHandlers(void)
- {
- OSErr err;
-
- // First, allocate a UPP for the core event handler...
-
- AEEventHandlerUPP eventUPP = NewAEEventHandlerProc(HandleAECore);
-
- if (eventUPP == nil) ACGIFatal("Could not allocate UPP for core AE handler.");
-
- // [1] open app...
-
- err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
- eventUPP, kOtherCoreEvent, false);
-
- if (err != noErr) ACGIFatal("Could not install 'open app' handler.");
-
- // [2] open doc...
-
- err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
- eventUPP, kOtherCoreEvent, false);
-
- if (err != noErr) ACGIFatal("Could not install 'open doc' handler.");
-
- // [3] print doc...
-
- err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
- eventUPP, kOtherCoreEvent, false);
-
- if (err != noErr) ACGIFatal("Could not install 'print doc' handler.");
-
- // [4] quit app...
-
- err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
- eventUPP, kQuitCoreEvent, false);
-
- if (err != noErr) ACGIFatal("Could not install 'quit app' handler.");
-
- // [5] sdoc event...
-
- eventUPP = NewAEEventHandlerProc(HandleSDOC);
-
- if (eventUPP == nil) ACGIFatal("Could not allocate UPP for SDOC handler.");
-
- err = AEInstallEventHandler(kWebSTAREventClass, kSDOCEvent,
- eventUPP, 0, false);
-
- if (err != noErr)
- ACGIFatal("Could not install 'search document' handler.");
- }
-
- // -----------------------------------------------------
-
- // Maximum number of threads...
-
- static unsigned long gMaxThreads = 10;
-
- // Are we refusing connections...
-
- static Boolean gRefusing = false;
-
- // Thread stack-size and creation options...
-
- static long gThreadStackSize = 0;
- static ThreadOptions gThreadOptions = kCreateIfNeeded | kFPUNotNeeded;
-
- // Private data structure used to pass AppleEvent information into the thread...
-
- typedef struct AEParams {
- AppleEvent event;
- AppleEvent reply;
- } AEParams;
-
- void SDOCThread(void *threadParam);
-
- OSErr ACGIReturnHandle(AppleEvent *reply, Handle h);
-
- // This handler is called when we get a WebSTAR request...we need to
- // create a thread to handle the request and get out...
-
- pascal OSErr HandleSDOC(AppleEvent *event, AppleEvent *reply, long refCon)
- {
- AEParams** params;
- ThreadID newThreadID;
-
- // [1] Are too many threads already running?
-
- if (gThreads >= gMaxThreads)
- return (ACGIReturnHandle(reply, gHTMLTooBusy));
-
- // [2] Are we refusing requests?
-
- if (gDone || gRefusing)
- return (ACGIReturnHandle(reply, gHTMLRefused));
-
- // [3] Okay to run, fork a new SDOC thread...
-
- gThreads++;
-
- params = (AEParams**) NewHandle(sizeof(AEParams));
-
- if (params == nil) return (errAEEventNotHandled);
-
- // [4] Copy the event information so we can pass it
- // in to the new thread for processing.
-
- (*params)->event = *event;
- (*params)->reply = *reply;
-
- // [5] Make a new thread..bail out (and dispose of memory) if we fail...
-
- if (NewThread(kCooperativeThread,
- (ThreadEntryProcPtr) SDOCThread,
- (void*) params,
- gThreadStackSize,
- gThreadOptions,
- nil,
- &newThreadID) != noErr) {
-
- DisposeHandle((Handle) params);
- return (errAEEventNotHandled);
- }
-
- // [6] Suspend the current event so we can accept new events.
-
- return (AESuspendTheCurrentEvent(event));
- }
-
- // -----------------------------------------------------
-
- #define kPathArgsKeyword keyDirectObject
- #define kSearchArgsKeyword 'kfor'
- #define kPostArgsKeyword 'post'
-
- #define kUsernameKeyword 'user'
- #define kPasswordKeyword 'pass'
- #define kFromUserKeyword 'frmu'
- #define kClientAddressKeyword 'addr'
- #define kServerAddressKeyword 'svnm'
- #define kServerIPPortKeyword 'svpt'
- #define kScriptNameKeyword 'scnm'
- #define kContentTypeKeyword 'ctyp'
- #define kReferrerKeyword 'refr'
- #define kUserAgentKeyword 'Agnt'
-
- #define kActionKeyword 'Kact'
- #define kActionPathKeyword 'Kapt'
- #define kMethodKeyword 'meth'
- #define kClientIPKeyword 'Kcip'
- #define kFullRequestKeyword 'Kfrq'
- #define kConnectionIDKeyword 'Kcid'
-
- // -----------------------------------------------------
-
- static Size ACGIParamSize(AppleEvent *event);
- OSErr ACGICopyArgs(AppleEvent *event, WWWRequest r);
- OSErr ACGIURLDecode(char *data, long *n, Handle *names, Handle *values);
-
- static void SDOCThread(void *threadParam)
- {
- WWWRequestRecord request;
- Size spaceNeeded;
- Size responseSize;
-
- OSErr err;
-
- // [1] Copy event, reply to local storage.
-
- AEParams** params = (AEParams**) threadParam;
-
- AppleEvent event = (*params)->event;
- AppleEvent reply = (*params)->reply;
-
- DisposeHandle((Handle) params);
-
- // [2] Initialize 'request' structure...
-
- memset(&request, 0, sizeof(request));
-
- // [3] Allocate storage for params/args.
-
- spaceNeeded = ACGIParamSize(&event);
- request.storage = NewHandleClear(spaceNeeded);
- if (request.storage == nil) {
- char msg[128];
-
- sprintf(msg, "SDOCThread: no storage memory: %lu bytes.", spaceNeeded);
- ACGILog(msg);
- err = ACGIReturnHandle(&reply, gHTMLNoMemory);
- gDone = true;
-
- goto Done;
- }
-
- HLockHi(request.storage);
-
- // [4] Copy params/args into position...
-
- err = ACGICopyArgs(&event, &request);
- if (err != noErr) goto Done;
-
- // [5] Decode URL-encoded SEARCH and POST arguments...
-
- if (strlen(*request.storage + (long) request.searchArgs) > 0) {
-
- err = ACGIURLDecode(
- *request.storage + (long) request.searchArgs,
- &request.searchNum,
- &request.searchNames,
- &request.searchValues);
-
- if (err != noErr) goto Done;
- }
-
- if (strlen(*request.storage + (long) request.postArgs) > 0) {
-
- err = ACGIURLDecode(
- *request.storage + (long) request.postArgs,
- &request.postNum,
- &request.postNames,
- &request.postValues);
-
- if (err != noErr) goto Done;
- }
-
- HUnlock(request.storage);
-
- // [6] Allocate HTML response...
-
- request.response = NewHandleClear(gHTTPHeaderLen);
-
- if (request.response == nil) {
- gDone = true;
- err = ACGIReturnHandle(&reply, gHTMLNoMemory);
-
- goto Done;
- }
-
- BlockMoveData(gHTTPHeader, *request.response, gHTTPHeaderLen);
-
- // [7] Call the custom processor...
-
- err = WWWProcess(&request);
-
- // [8] Put the response into the reply and resume the Apple event...
-
- Done:
-
- if (request.storage != nil) DisposeHandle(request.storage);
- if (request.searchNames != nil)
- DisposeHandle(request.searchNames);
- if (request.searchValues != nil)
- DisposeHandle(request.searchValues);
- if (request.postNames != nil)
- DisposeHandle(request.postNames);
- if (request.postValues != nil)
- DisposeHandle(request.postValues);
-
- responseSize = GetHandleSize(request.response);
-
- if (err == noErr && request.response != nil
- && responseSize > gHTTPHeaderLen) {
- err = ACGIReturnHandle(&reply, request.response);
- }
- else { switch (err) {
- case errWWWNoMemory:
- err = ACGIReturnHandle(&reply, gHTMLNoMemory);
- break;
- case errWWWRefused:
- err = ACGIReturnHandle(&reply, gHTMLRefused);
- break;
- case errWWWTooBusy:
- err = ACGIReturnHandle(&reply, gHTMLTooBusy);
- break;
- case errWWWUnexpected:
- err = ACGIReturnHandle(&reply, gHTMLUnexpectedError);
- break;
- default:
- err = ACGIReturnHandle(&reply, gHTMLUnexpectedError);
- break; }
- }
-
- if (request.response != nil) DisposeHandle(request.response);
-
- // [9] Put error code into AppleEvent (if needed)...
-
- if (err != noErr) {
- long errorResult = err; // Must be long integer.
-
- AEPutParamPtr(&reply, keyErrorNumber,
- typeLongInteger, &errorResult, sizeof(long));
- }
-
- // [10] Resume the event, decrement running thread count, write to the log…
-
- AEResumeTheCurrentEvent(&event, &reply,
- (AEEventHandlerUPP) kAENoDispatch, 0);
-
- gThreads--;
-
- ACGILog("Done.");
-
- return;
- }
-
- // -----------------------------------------------------
-
- #define ACGI_GET_SIZE(what) \
- err = AESizeOfParam(event, (what), &typeCode, &dataSize); \
- if (err == noErr) spaceNeeded += dataSize + 1; \
- if (err == errAEDescNotFound) spaceNeeded++;
-
- static Size ACGIParamSize(AppleEvent *event)
- {
- Size spaceNeeded = 0;
- Size dataSize;
- DescType typeCode;
- OSErr err;
-
- ACGI_GET_SIZE(kPathArgsKeyword);
- ACGI_GET_SIZE(kSearchArgsKeyword);
-
- ACGI_GET_SIZE(kUsernameKeyword);
- ACGI_GET_SIZE(kPasswordKeyword);
- ACGI_GET_SIZE(kFromUserKeyword);
- ACGI_GET_SIZE(kClientAddressKeyword);
- ACGI_GET_SIZE(kServerAddressKeyword);
- ACGI_GET_SIZE(kServerIPPortKeyword);
- ACGI_GET_SIZE(kScriptNameKeyword);
- ACGI_GET_SIZE(kContentTypeKeyword);
- ACGI_GET_SIZE(kReferrerKeyword);
- ACGI_GET_SIZE(kUserAgentKeyword);
-
- ACGI_GET_SIZE(kActionKeyword);
- ACGI_GET_SIZE(kActionPathKeyword);
- ACGI_GET_SIZE(kMethodKeyword);
- ACGI_GET_SIZE(kClientIPKeyword);
- ACGI_GET_SIZE(kFullRequestKeyword);
-
- ACGI_GET_SIZE(kPostArgsKeyword);
-
- spaceNeeded += 11; // For ConnectionID string;
-
- return (spaceNeeded);
- }
-
- static OSErr ACGIOneArg(AppleEvent *event, AEKeyword what, char **where, char *pStart, char **p, char *pEnd)
- {
- Size dataSize;
- DescType typeCode;
-
- OSErr err = AEGetParamPtr(event, what, typeChar, &typeCode, *p, pEnd - *p, &dataSize);
-
- if (err != noErr && err != errAEDescNotFound) return (err);
-
- *where = (char *) (*p - pStart);
-
- if (err != errAEDescNotFound) *p += dataSize;
-
- (*p)++;
-
- return (noErr);
- }
-
- #define ACGI_GET_ARG(what, where) \
- err = ACGIOneArg(event, (what), &where, pStart, &p, pEnd); \
- if (err != noErr) return (err);
-
- OSErr ACGICopyArgs(AppleEvent *event, WWWRequest r)
- {
- char *pStart, *p, *pEnd;
- OSErr err;
-
- pStart = *r->storage;
- p = pStart;
- pEnd = pStart + GetHandleSize(r->storage) - 1;
-
- ACGI_GET_ARG(kPathArgsKeyword, r->pathArgs);
- ACGI_GET_ARG(kSearchArgsKeyword, r->searchArgs);
-
- ACGI_GET_ARG(kUsernameKeyword, r->username);
- ACGI_GET_ARG(kPasswordKeyword, r->password);
- ACGI_GET_ARG(kFromUserKeyword, r->fromUser);
- ACGI_GET_ARG(kClientAddressKeyword, r->clientAddress);
- ACGI_GET_ARG(kServerAddressKeyword, r->serverName);
- ACGI_GET_ARG(kServerIPPortKeyword, r->serverPort);
- ACGI_GET_ARG(kScriptNameKeyword, r->scriptName);
- ACGI_GET_ARG(kContentTypeKeyword, r->contentType);
- ACGI_GET_ARG(kReferrerKeyword, r->referer);
- ACGI_GET_ARG(kUserAgentKeyword, r->userAgent);
-
- ACGI_GET_ARG(kActionKeyword, r->action);
- ACGI_GET_ARG(kActionPathKeyword, r->actionPath);
- ACGI_GET_ARG(kMethodKeyword, r->method);
- ACGI_GET_ARG(kClientIPKeyword, r->clientIP);
- ACGI_GET_ARG(kFullRequestKeyword, r->fullRequest);
- ACGI_GET_ARG(kConnectionIDKeyword, r->connectionID);
- ACGI_GET_ARG(kPostArgsKeyword, r->postArgs);
-
- r->event = event;
-
- return (noErr);
- }
-
- // -----------------------------------------------------
-
- Boolean ACGIDecodeCStr(char *s);
-
- OSErr ACGIURLDecode(char *data, long *n, Handle *names, Handle *values)
- {
- char *pStart, *p, *pEnd, **nameList, **valueList;
- unsigned long i = 1;
- char lastDelim = '&';
-
- pStart = data;
- pEnd = pStart + strlen(data);
- p = pStart;
-
- // First, count up the number of arguments...
-
- while (*p != 0) {
- if (*p == '&') i++;
- p++;
- }
-
- // Try to allocate memory to hold them...
-
- *names = NewHandleClear(i * sizeof(char *));
- if (*names == nil) {
- ACGILog("ACGIURLDecode: no memory for POST names.");
- return(memFullErr);
- }
-
- *values = NewHandleClear(i * sizeof(char *));
- if (*names == nil) {
- ACGILog("ACGIURLDecode: no memory for POST values.");
- return(memFullErr);
- }
-
- // Make some nice clean array pointers out of the handles.
-
- nameList = ((char **) **names);
- valueList = ((char **) **values);
-
- // Scan for name=value pairs and record their positions.
-
- *n = i;
-
- p = pStart;
- i = 0;
-
- do {
- while (*p != '&' && *p != '=' && *p != 0) p++;
-
- // found a name...record in nameList...
-
- if (lastDelim == '&' && *p == '=') {
- nameList[i] = (char *) (pStart - data); *p++ = 0;
-
- if (!ACGIDecodeCStr(pStart)) return (2);
-
- pStart = p;
-
- lastDelim = '=';
- }
-
- // found a value...record in valueList...
-
- else if (lastDelim == '=' && (*p == '&' || *p == 0)) {
- valueList[i++] = (char *) (pStart - data); *p++ = 0;
-
- if (!ACGIDecodeCStr(pStart)) return (2);
-
- pStart = p;
-
- lastDelim = '&';
- }
-
- // error in the post argument string...fatal...
-
- else {
- ACGILog("ACGIURLDecode: failed parsing post arguments.");
- return (errWWWUnexpected);
- }
-
- } while (i < *n && p < pEnd);
-
- return (noErr);
- }
-
- static Boolean ACGIDecodeCStr(char *s)
- {
- long n = strlen(s);
- long i, j;
- char c1, c2;
- Handle hXLAT = Get1Resource('xlat', 1000);
-
- for (i = j = 0; i < n; i++) {
-
- // '+' signs become blanks...
-
- if (s[i] == '+')
- s[j++] = ' ';
-
- // '%' signals start of 3-character hex sequence...
-
- else if (s[i] == '%') {
- if (i + 2 >= n) return (false);
-
- c1 = toupper(s[i + 1]);
- c2 = toupper(s[i + 2]);
-
- i += 2;
-
- if (!isxdigit(c1)) return (false);
- if (!isxdigit(c2)) return (false);
-
- if (isdigit(c1))
- c1 -= '0';
- else
- c1 = (c1 - 'A') + 10;
-
- if (isdigit(c2))
- c2 -= '0';
- else
- c2 = (c2 - 'A') + 10;
-
- s[j++] = (c1 << 4) | c2;
- }
-
- // All else gets passed through as long as it's
- // not a control character (0x00 - 0x1F and 0x7F).
- // The only exceptions are carriage returns (0x0D)
- // and line-feeds (0x0A). They all get mapped to
- // carriage returns except when they appear as
- // carriage return/line feed pairs. They get
- // replaced by single carriage returns.
-
- else {
- if (!iscntrl(s[i]) || s[i] == 0x0D || s[i] == 0x0A) {
- if (s[i] < ' ' && s[i + 1] < ' ') {
- s[j++] = 0x0D; i++;
- }
- else if (s[i] == 0x0A)
- s[j++] = 0x0D;
- else
- s[j++] = s[i];
- }
- }
- }
-
- // Terminate the string...
-
- s[j] = 0;
-
- // Now transliterate it from ISO Latin-1 to Macintosh Roman...
-
- if (hXLAT != nil) {
- for (i = 0; i < strlen(s); i++) {
- s[i] = ((char *) *hXLAT)[(unsigned char) s[i]];
- }
- }
-
- return (true);
- }
-
- // -----------------------------------------------------
-
- // [1] Shut down the ACGI as soon as all current threads are finished.
-
- void ACGIShutdown(void)
- {
- gDone = true;
- }
-
- // [2] Is the ACGI shutting down?
-
- Boolean ACGIIsShuttingdown(void)
- {
- return (gDone);
- }
-
- // [3] Toggle acceptance/rejection of requests.
-
- Boolean ACGIRefuse(Boolean refuse)
- {
- Boolean oldRefuse = gRefusing;
-
- gRefusing = refuse;
-
- return (oldRefuse);
- }
-
- // [4] Get number of active threads.
-
- unsigned long ACGIGetRunningThreads(void)
- {
- return (gThreads);
- }
-
- // [5] Get maximum number of threads able to run at once.
-
- unsigned long ACGIGetMaxThreads(void)
- {
- return (gMaxThreads);
- }
-
- // [6] Set the maximum number of allowed threads.
-
- void ACGISetMaxThreads(unsigned long newThreads)
- {
- gMaxThreads = newThreads;
- }
-
- // [7] Get current sleep settings.
-
- void ACGIGetSleeps(long *whenThreads, long *whenIdle)
- {
- *whenThreads = gThreadSleep;
- *whenIdle = gIdleSleep;
- }
-
- // [8] Set new sleep settings.
-
- void ACGISetSleeps(long whenThreads, long whenIdle)
- {
- gThreadSleep = whenThreads;
- gIdleSleep = whenIdle;
- }
-
- // [9] Get current time between calls to WaitNextEvent().
-
- long ACGIGetWNEDelta(void)
- {
- return (gWNEDelta);
- }
-
- // [10] Set current time between calls to WaitNextEvent().
-
- void ACGISetWNEDelta(long newDelta)
- {
- gWNEDelta = newDelta;
- }
-
- // [11] Get current thread stack size.
-
- void ACGIGetThreadParams(Size *stack, ThreadOptions *options)
- {
- *stack = gThreadStackSize;
- *options = gThreadOptions;
- return;
- }
-
- // [12] Set thread stack size.
-
- void ACGISetThreadParams(Size stack, ThreadOptions options)
- {
- gThreadStackSize = stack;
- gThreadOptions = options;
- }
-
- // [13] Get a pointer to the standard HTTP header.
-
- const char *ACGIGetHTTPHeader(void)
- {
- return (gHTTPHeader);
- }
-
- // [14] Put a handle into a reply.
-
- OSErr ACGIReturnHandle(AppleEvent *reply, Handle h)
- {
- OSErr err;
-
- if (h == nil) return (noErr);
-
- HLockHi(h);
- err = AEPutParamPtr(reply, keyDirectObject, typeChar,
- *h, GetHandleSize(h));
- HUnlock(h);
-
- return (err);
- }
-
- // -----------------------------------------------------
-
- // [1] Lock down your 'request' parameters before accessing contents.
-
- Boolean HTTPLockParams(WWWRequest r)
- {
- long i;
- char **nameList;
- char **valueList;
-
- if (r->isLocked) return (true);
-
- HLockHi(r->storage);
-
- r->isLocked = true;
-
- // Editor's Note: the following code is a bit obscure, so here's an explanation,
- // hopefully it will save you some tim if you're trying to figure it out, like I did.
- // Initially, each of these "pointer" fields contains an offset into the "storage" string.
- // Below we add to each one the pointer to the start of "storage." The result is
- // that when we're done, each field contains the correct pointer into "storage."
- // The casting is necessary to make it compile, but does not reflect reality: the
- // operand on the left is the offset, that on the right is the pointer, even though
- // we're telling the compiler exactly the opposite. Clever trick, but it sure is hard to
- // read...
- // dkj
- r->pathArgs += (unsigned long)*r->storage;
- r->username += (unsigned long)*r->storage;
- r->password += (unsigned long)*r->storage;
- r->fromUser += (unsigned long)*r->storage;
- r->clientAddress += (unsigned long)*r->storage;
- r->serverName += (unsigned long)*r->storage;
- r->serverPort += (unsigned long)*r->storage;
- r->scriptName += (unsigned long)*r->storage;
- r->contentType += (unsigned long)*r->storage;
- r->referer += (unsigned long)*r->storage;
- r->userAgent += (unsigned long)*r->storage;
- r->action += (unsigned long)*r->storage;
- r->actionPath += (unsigned long)*r->storage;
- r->method += (unsigned long)*r->storage;
- r->clientIP += (unsigned long)*r->storage;
- r->fullRequest += (unsigned long)*r->storage;
- r->connectionID += (unsigned long)*r->storage;
-
- r->searchArgs += (unsigned long)*r->storage;
-
- if (r->searchNum > 0) {
- HLockHi(r->searchNames);
- HLockHi(r->searchValues);
-
- nameList = ((char **) *(r->searchNames));
- valueList = ((char **) *(r->searchValues));
-
- for (i = 0; i < r->searchNum; i++) {
- nameList[i] += (unsigned long)r->searchArgs;
- valueList[i] += (unsigned long)r->searchArgs;
- }
- }
-
- r->postArgs += (unsigned long)*r->storage;
-
- if (r->postNum > 0) {
- HLockHi(r->postNames);
- HLockHi(r->postValues);
-
- nameList = ((char **) *(r->postNames));
- valueList = ((char **) *(r->postValues));
-
- for (i = 0; i < r->postNum; i++) {
- nameList[i] += (unsigned long)r->postArgs;
- valueList[i] += (unsigned long)r->postArgs;
- }
- }
-
- return (true);
- }
-
- // [2] Unlock your request parameters.
-
- void HTTPUnlockParams(WWWRequest r)
- {
- long i;
- char **nameList;
- char **valueList;
-
- if (!r->isLocked) return;
-
- r->isLocked = false;
-
- if (r->searchNum > 0) {
- nameList = ((char **) *(r->searchNames));
- valueList = ((char **) *(r->searchValues));
-
- for (i = 0; i < r->searchNum; i++) {
- nameList[i] -= (unsigned long)r->searchArgs;
- valueList[i] -= (unsigned long)r->searchArgs;
- }
-
- HUnlock(r->searchNames);
- HUnlock(r->searchValues);
- }
-
- if (r->postNum > 0) {
- nameList = ((char **) *(r->postNames));
- valueList = ((char **) *(r->postValues));
-
- for (i = 0; i < r->postNum; i++) {
- nameList[i] -= (unsigned long)r->postArgs;
- valueList[i] -= (unsigned long)r->postArgs;
- }
-
- HUnlock(r->postNames);
- HUnlock(r->postValues);
- }
-
- // Editor's Note: Similarly to above in the HTTPLockParams routine, there's some
- // fancy and non-obvious pointer manipulation going on here. See explanation above.
- r->pathArgs -= (unsigned long)*r->storage;
- r->username -= (unsigned long)*r->storage;
- r->password -= (unsigned long)*r->storage;
- r->fromUser -= (unsigned long)*r->storage;
- r->clientAddress -= (unsigned long)*r->storage;
- r->serverName -= (unsigned long)*r->storage;
- r->serverPort -= (unsigned long)*r->storage;
- r->scriptName -= (unsigned long)*r->storage;
- r->contentType -= (unsigned long)*r->storage;
- r->referer -= (unsigned long)*r->storage;
- r->userAgent -= (unsigned long)*r->storage;
- r->action -= (unsigned long)*r->storage;
- r->actionPath -= (unsigned long)*r->storage;
- r->method -= (unsigned long)*r->storage;
- r->clientIP -= (unsigned long)*r->storage;
- r->fullRequest -= (unsigned long)*r->storage;
- r->connectionID -= (unsigned long)*r->storage;
-
- r->searchArgs -= (unsigned long)*r->storage;
- r->postArgs -= (unsigned long)*r->storage;
-
- HUnlock(r->storage);
-
- return;
- }
-
- // [3] Get a pointer to one of the parameter strings.
- // This leaves 'r' locked.
-
- const char *HTTPGetParam(WWWRequest r, WWWParameter par)
- {
- const char **p;
-
- if (par < p_path_args || par > p_connection_id) return "";
-
- if (!r->isLocked) HTTPLockParams(r);
-
- p = &r->pathArgs + par;
-
- return (*p);
- }
-
- // [4] Get the integer value of a parameter. Result is returned
- // in 'i'. Function returns 'false' if the parameter is
- // not an integer.
-
- Boolean HTTPGetLong(WWWRequest r, WWWParameter par, long *i)
- {
- const char *p;
- Boolean wasntLocked = !r->isLocked;
- Boolean isValid = false;
-
- if (par < p_path_args || par > p_connection_id) return 0;
-
- *i = 0;
-
- p = HTTPGetParam(r, par);
-
- if (strlen(p) > 0) {
- char *q = (char *) p;
-
- while (*q == ' ') q++;
-
- if (*q == '+' || *q == '-') q++;
-
- while (*q != 0) if (!isdigit(*q++)) goto Done;
-
- sscanf(p, "%ld", i);
-
- isValid = true;
- }
-
- Done:
- if (wasntLocked) HTTPUnlockParams(r);
-
- return (isValid);
- }
-
- // [5] Copy parameter text into character variable 'result'.
- // Length of your character variable is in 'len', the
- // actual length of the parameter is returned in
- // 'actualLen'. Function returns 'false' if the
- // parameter identifier 'par' is invalid.
-
- Boolean HTTPCopyParam(WWWRequest r, WWWParameter par, char *result, long len, long *actualLen)
- {
- const char *p;
- Boolean wasntLocked = !r->isLocked;
-
- if (par < p_path_args || par > p_connection_id) {
- result[0] = 0;
- *actualLen = 0;
- return (false);
- }
-
- p = HTTPGetParam(r, par);
-
- *actualLen = strlen(p);
- strncpy(result, p, len);
-
- if (wasntLocked) HTTPUnlockParams(r);
-
- return (true);
- }
-
- // [6/7] Get number of SEARCH/POST arguments.
-
- long HTTPGetNumSrchArgs(WWWRequest r)
- {
- return r->searchNum;
- }
-
- long HTTPGetNumPostArgs(WWWRequest r)
- {
- return r->postNum;
- }
-
- // [8/9] Get a SEARCH/POST argument by absolute position. 'index' is between
- // 1 and the total number of SEARCH/POST arguments. 'name' receives the
- // name of the argument at position 'index' and 'value' receives the value.
- // The lengths of the character arrays 'name' and 'value' are in 'nameLen'
- // and 'valueLen'. The actual lengths of the items are returned in
- // 'actualNameLen' and 'actualValueLen'. Function returns 'false' if 'index'
- // is out of range.
-
- Boolean HTTPGetSrchArgAt(WWWRequest r, long index, char *name, long nameLen, long *actualNameLen, char *value, long valueLen, long *actualValueLen)
- {
- const char *p;
- long n = r->searchNum;
- char **nameList;
- char **valueList;
- Boolean wasntLocked = !r->isLocked;
-
- // Any arguments to look at?
-
- if (n < 1 || index < 1 || index > n) {
- name[0] = 0;
- *actualNameLen = 0;
-
- value[0] = 0;
- *actualValueLen = 0;
-
- return (false);
- }
-
- // Get requested item...
-
- if (wasntLocked) HTTPLockParams(r);
-
- nameList = ((char **) *(r->searchNames));
- valueList = ((char **) *(r->searchValues));
-
- p = nameList[index - 1];
- *actualNameLen = strlen(p);
- strncpy(name, p, nameLen);
-
- p = valueList[index - 1];
- *actualValueLen = strlen(p);
- strncpy(value, p, valueLen);
-
- if (wasntLocked) HTTPUnlockParams(r);
-
- return (true);
- }
-
- Boolean HTTPGetPostArgAt(WWWRequest r, long index, char *name, long nameLen, long *actualNameLen, char *value, long valueLen, long *actualValueLen)
- {
- const char *p;
- long n = r->postNum;
- char **nameList;
- char **valueList;
- Boolean wasntLocked = !r->isLocked;
-
- // Any arguments to look at?
-
- if (n < 1 || index < 1 || index > n) {
- name[0] = 0;
- *actualNameLen = 0;
-
- value[0] = 0;
- *actualValueLen = 0;
-
- return (false);
- }
-
- // Get requested item...
-
- if (wasntLocked) HTTPLockParams(r);
-
- nameList = ((char **) *(r->postNames));
- valueList = ((char **) *(r->postValues));
-
- p = nameList[index - 1];
- *actualNameLen = strlen(p);
- strncpy(name, p, nameLen);
-
- p = valueList[index - 1];
- *actualValueLen = strlen(p);
- strncpy(value, p, valueLen);
-
- if (wasntLocked) HTTPUnlockParams(r);
-
- return (true);
- }
-
- // [10/11] Get number of SEARCH/POST arguments that have the same field
- // name 'name'. Number is returned in 'numValues'. Function return
- // 'false' if there is no SEARCH/POST argument called 'name'.
-
- Boolean HTTPGetSrchArgCount(WWWRequest r, char *name, long *numValues)
- {
- long i;
- long n = r->searchNum;
- char **nameList;
- Boolean wasntLocked = !r->isLocked;
-
- *numValues = 0;
-
- // Any arguments to look at?
-
- if (n < 1) return (false);
-
- // Scan to count the number of times the name appears...
-
- if (wasntLocked) HTTPLockParams(r);
-
- nameList = ((char **) *(r->searchNames));
-
- for (i = 0; i < n; i++) {
- if (strcmp(name, nameList[i]) == 0) {
- (*numValues)++;
- }
- }
-
- if (wasntLocked) HTTPUnlockParams(r);
-
- if (*numValues >= 1)
- return (true);
- else
- return (false);
- }
-
- Boolean HTTPGetPostArgCount(WWWRequest r, char *name, long *numValues)
- {
- long i;
- long n = r->postNum;
- char **nameList;
- Boolean wasntLocked = !r->isLocked;
-
- *numValues = 0;
-
- // Any arguments to look at?
-
- if (n < 1) return (false);
-
- // Scan to count the number of times the name appears...
-
- if (wasntLocked) HTTPLockParams(r);
-
- nameList = ((char **) *(r->postNames));
-
- for (i = 0; i < n; i++) {
- if (strcmp(name, nameList[i]) == 0) {
- (*numValues)++;
- }
- }
-
- if (wasntLocked) HTTPUnlockParams(r);
-
- if (*numValues >= 1)
- return (true);
- else
- return (false);
- }
-
- // [12/13] Try to get instance 'index' of a multi-valued SEARCH/POST argument.
- // Function returns empty string if 'index' is out of range or if 'name' doesn't
- // exist. Function leaves 'r' locked on exit.
-
- const char *HTTPGetMultipleSrchArg(WWWRequest r, char *name, long index)
- {
- long i, count = 0;
- long n = r->searchNum;
- char **nameList;
- char **valueList;
- Boolean wasntLocked = !r->isLocked;
-
- // Any arguments to look at?
-
- if (n < 1 || index < 1 || index > n) return "";
-
- // Scan to locate requested item...
-
- if (wasntLocked) HTTPLockParams(r);
-
- nameList = ((char **) *(r->searchNames));
- valueList = ((char **) *(r->searchValues));
-
- for (i = 0; i < n; i++) {
- if (strcmp(name, nameList[i]) == 0) {
- count++;
- if (count == index) {
- return (valueList[i]);
- }
- }
- }
-
- return "";
- }
-
- const char *HTTPGetMultiplePostArg(WWWRequest r, char *name, long index)
- {
- long i, count = 0;
- long n = r->postNum;
- char **nameList;
- char **valueList;
- Boolean wasntLocked = !r->isLocked;
-
- // Any arguments to look at?
-
- if (n < 1 || index < 1 || index > n) return "";
-
- // Scan to locate requested item...
-
- if (wasntLocked) HTTPLockParams(r);
-
- nameList = ((char **) *(r->postNames));
- valueList = ((char **) *(r->postValues));
-
- for (i = 0; i < n; i++) {
- if (strcmp(name, nameList[i]) == 0) {
- count++;
- if (count == index) {
- return (valueList[i]);
- }
- }
- }
-
- return "";
- }
-
- // [14/15] Get integer value of instance 'index' of a multi-valued SEARCH/POST
- // argument called 'name'. Function returns value in 'i'. Function returns
- // 'false' if 'index' is out of range or the argument is not an integer.
-
- Boolean HTTPGetLongMultipleSrchArg(WWWRequest r, char *name, long index, long *i)
- {
- const char *p;
- Boolean wasntLocked = !r->isLocked;
- Boolean isValid = false;
-
- *i = 0;
-
- p = HTTPGetMultipleSrchArg(r, name, index);
-
- if (strlen(p) > 0) {
- char *q = (char *) p;
-
- while (*q == ' ') q++;
-
- if (*q == '+' || *q == '-') q++;
-
- while (*q != 0) if (!isdigit(*q++)) goto Done;
-
- sscanf(p, "%ld", i);
-
- isValid = true;
- }
-
- Done:
- if (wasntLocked) HTTPUnlockParams(r);
-
- return (isValid);
- }
-
- Boolean HTTPGetLongMultiplePostArg(WWWRequest r, char *name, long index, long *i)
- {
- const char *p;
- Boolean wasntLocked = !r->isLocked;
- Boolean isValid = false;
-
- *i = 0;
-
- p = HTTPGetMultiplePostArg(r, name, index);
-
- if (strlen(p) > 0) {
- char *q = (char *) p;
-
- while (*q == ' ') q++;
-
- if (*q == '+' || *q == '-') q++;
-
- while (*q != 0) if (!isdigit(*q++)) goto Done;
-
- sscanf(p, "%ld", i);
-
- isValid = true;
- }
-
- Done:
- if (wasntLocked) HTTPUnlockParams(r);
-
- return (isValid);
- }
-
- // [16/17] Copy the contents of instance 'index' of a multi-valued SEARCH/POST
- // argument called 'name'. Function returns text in 'value'. Length of 'value'
- // string is in 'len', actual length of the value string is returned in 'actualLen'
- // Function returns 'false' if 'index' is out of range or 'name' does not exist.
-
- Boolean HTTPCopyMultipleSrchArg(WWWRequest r, char *name, long index, char *value, long len, long *actualLen)
- {
- long i, count = 0;
- const char *p;
- long n = r->searchNum;
- char **nameList;
- char **valueList;
- Boolean wasntLocked = !r->isLocked;
-
- // Any arguments to look at?
-
- if (n < 1 || index < 1 || index > n) {
- value[0] = 0;
- *actualLen = 0;
- return (false);
- }
-
- // Scan to locate requested item...
-
- if (wasntLocked) HTTPLockParams(r);
-
- nameList = ((char **) *(r->searchNames));
- valueList = ((char **) *(r->searchValues));
-
- for (i = 0; i < n; i++) {
- if (strcmp(name, nameList[i]) == 0) {
- count++;
- if (count == index) {
- p = valueList[i];
- *actualLen = strlen(p);
- strncpy(value, p, len);
- if (wasntLocked) HTTPUnlockParams(r);
- return (true);
- }
- }
- }
-
- value[0] = 0;
- *actualLen = 0;
-
- if (wasntLocked) HTTPUnlockParams(r);
-
- return (false);
- }
-
- Boolean HTTPCopyMultiplePostArg(WWWRequest r, char *name, long index, char *value, long len, long *actualLen)
- {
- long i, count = 0;
- const char *p;
- long n = r->postNum;
- char **nameList;
- char **valueList;
- Boolean wasntLocked = !r->isLocked;
-
- // Any arguments to look at?
-
- if (n < 1 || index < 1 || index > n) {
- value[0] = 0;
- *actualLen = 0;
- return (false);
- }
-
- // Scan to locate requested item...
-
- if (wasntLocked) HTTPLockParams(r);
-
- nameList = ((char **) *(r->postNames));
- valueList = ((char **) *(r->postValues));
-
- for (i = 0; i < n; i++) {
- if (strcmp(name, nameList[i]) == 0) {
- count++;
- if (count == index) {
- p = valueList[i];
- *actualLen = strlen(p);
- strncpy(value, p, len);
- if (wasntLocked) HTTPUnlockParams(r);
- return (true);
- }
- }
- }
-
- value[0] = 0;
- *actualLen = 0;
-
- if (wasntLocked) HTTPUnlockParams(r);
-
- return (false);
- }
-
- // -----------------------------------------------------
-
- // [1] Get the handle that holds the HTML response page.
-
- Handle HTMLGetResponseHandle(WWWRequest r)
- {
- return (r->response);
- }
-
- // [2] Clear out the current response page (except for the
- // HTTP header, and start over.
-
- OSErr HTMLClearPage(Handle r)
- {
- SetHandleSize(r, gHTTPHeaderLen);
-
- return (MemError());
- }
-
- // [3] Append contents of handle 'h' to response page.
-
- OSErr HTMLAppendHandle(Handle r, Handle h)
- {
- if (h != nil && *h != nil && GetHandleSize(h) > 0)
- return (HandAndHand(h, r));
- else
- return (noErr);
- }
-
- // [4] Append TEXT resource (ID=iTEXTResID) to response page.
-
- OSErr HTMLAppendTEXT(Handle r, long iTEXTResID)
- {
- Handle h = Get1Resource('TEXT', iTEXTResID);
-
- OSErr err = ResError();
-
- if (h == nil || err != noErr) {
- Str31 s;
- NumToString(iTEXTResID, s);
- s[s[0] + 1] = 0;
-
- ACGILog("Cound not load requested TEXT resource. ID was:");
- ACGILog((char *) &s[1]);
-
- if (err != noErr)
- return (err);
- else
- return (resNotFound);
- }
-
- return (HandAndHand(h, r));
- }
-
- // [5] Append STR resource (ID=iSTRResID) to the response page.
-
- OSErr HTMLAppendString(Handle r, long iSTRResID)
- {
- StringHandle h = GetString(iSTRResID);
-
- OSErr err = ResError();
-
- if (h == nil || err != noErr) {
- Str31 s;
- NumToString(iSTRResID, s);
- s[s[0] + 1] = 0;
-
- ACGILog("Cound not load requested STR resource. ID was:");
- ACGILog((char *) &s[1]);
-
- if (err != noErr)
- return (err);
- else
- return (resNotFound);
- }
-
- HLockHi((Handle) h);
- err = PtrAndHand(*h + 1, r, **h);
- HUnlock((Handle) h);
-
- return (err);
- }
-
- // [6] Append string at location 'index' in STR# resource
- // (ID=iSTRResID) to the response page.
-
- OSErr HTMLAppendIndString(Handle r, long iSTRResID, long index)
- {
- Str255 theStr;
- OSErr err;
-
- GetIndString(theStr, iSTRResID, index);
-
- if (theStr[0] == 0) {
- ACGILog("Request to append empty string from STR# resource. Resource number:");
-
- NumToString(iSTRResID, theStr);
- theStr[theStr[0] + 1] = 0;
- ACGILog((char *) &theStr[1]);
-
- ACGILog("STR# index was:");
-
- NumToString(index, theStr);
- theStr[theStr[0] + 1] = 0;
- ACGILog((char *) &theStr[1]);
- }
-
- err = PtrAndHand(&theStr[1], r, theStr[0]);
-
- return (err);
- }
-
- // [7] Append local file to response page.
-
- OSErr HTMLAppendFile(Handle r, char *localFileName)
- {
- Size theLen, origLen;
- char *text = nil;
- OSErr err;
-
- // Open the file in the directory our ACGI is running in.
-
- FILE *f = fopen(localFileName, "rb");
-
- if (f == NULL) {
- ACGILog("Could not open HTML file to append to response. File name was:");
- ACGILog(localFileName);
- return (fnfErr);
- }
-
- // Determine number of characters in the file.
-
- fseek(f, 0L, SEEK_END);
-
- theLen = ftell(f);
-
- if (theLen <= 0) {
- ACGILog("Could not determine size of HTML file for response. File name was:");
- ACGILog(localFileName);
- return (fnfErr);
- }
-
- // Rewind to the start of the file.
-
- fseek(f, 0L, SEEK_SET);
-
- // Extend the response handle.
-
- origLen = GetHandleSize(r);
-
- SetHandleSize(r, origLen + theLen);
-
- err = MemError();
-
- if (err != noErr) {
- fclose(f);
- ACGILog("Ran out of memory appending HTML file to response. File name was:");
- ACGILog(localFileName);
- return (err);
- }
-
- // Add the file contents to the response.
-
- HLockHi(r);
- fread(*r + origLen, theLen, 1, f);
- HUnlock(r);
-
- fclose(f);
-
- return (noErr);
- }
-
- // [8] Append C-string to response page.
-
- OSErr HTMLAppendCString(Handle r, char *cString)
- {
- return (PtrAndHand(cString, r, strlen(cString)));
- }
-
- // [9] Append Pascal-string to response page.
-
- OSErr HTMLAppendPString(Handle r, StringPtr pString)
- {
- return (PtrAndHand(&pString[1], r, pString[0]));
- }
-
- // [10] Append text buffer of length 'len' to response page.
-
- OSErr HTMLAppendBuffer(Handle r, char *buffer, long len)
- {
- return (PtrAndHand(buffer, r, len));
- }
-